﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using devtm.Configuration;
using System.ComponentModel;
using System.Reflection;
using System.Configuration;
using System.Globalization;
using System.Text.RegularExpressions;
using devtm.Configuration.Models;

namespace devtm.Helpers
{


    public static class ConfigurationHelper
    {


        public static T GetSection<T>(string Sectionname) where T : System.Configuration.ConfigurationElement
        {
            try
            {

                T config = (T)System.Configuration.ConfigurationManager.GetSection(Sectionname);

                if (config == null)
                    throw new MissingConfigurationSectionException(typeof(T), Sectionname);

                return config;

            }
            catch (Exception ex)
            {
                throw new MissingConfigurationSectionException(typeof(T), Sectionname, ex);
            }

        }


        /// <summary>
        /// Resolves the name.
        /// </summary>
        /// <param name="p">The p.</param>
        /// <returns></returns>
        public static string ResolveName(this MemberInfo p)
        {
            string name = p.Name;
            DisplayNameAttribute d = (DisplayNameAttribute)Attribute.GetCustomAttribute(p, typeof(DisplayNameAttribute));

            return d != null ? d.DisplayName : name;
        }

        /// <summary>
        /// Resolves the name.
        /// </summary>
        /// <param name="p">The p.</param>
        /// <returns></returns>
        public static string ResolveName(this PropertyInfo p)
        {
            string name = p.Name;
            DisplayNameAttribute d = (DisplayNameAttribute)Attribute.GetCustomAttribute(p, typeof(DisplayNameAttribute));

            return d != null ? d.DisplayName : name;
        }

        /// <summary>
        /// Resolves the name.
        /// </summary>
        /// <param name="p">The p.</param>
        /// <returns></returns>
        public static string ResolveConfigurationName(this PropertyInfo p)
        {


            DisplayNameAttribute d = (DisplayNameAttribute)Attribute.GetCustomAttribute(p, typeof(DisplayNameAttribute));
            if (d != null && !string.IsNullOrEmpty(d.DisplayName))
                return d.DisplayName;

            ConfigurationPropertyAttribute l1 =
                (ConfigurationPropertyAttribute)Attribute.GetCustomAttribute(p, typeof(ConfigurationPropertyAttribute));
            if (l1 != null && !string.IsNullOrEmpty(l1.Name))
                return l1.Name;

            return p.Name;
        }

        /// <summary>
        /// Resolves the description.
        /// </summary>
        /// <param name="p">The p.</param>
        /// <returns></returns>
        public static string ResolveDescription(this MemberInfo p)
        {
            string name = p.Name;

            DescriptionAttribute d = (DescriptionAttribute)Attribute.GetCustomAttribute(p, typeof(DescriptionAttribute));

            return d != null ? d.Description: name;
        }


        
        public static void CreateTemplateCode(this Type type, string Namespace, string filepath, bool Override, string context)
        {

            //string test = string.Format(CultureInfo.CurrentCulture, "{0}I{1}", Namespace, type.Name);
            //if (Type.GetType(test) != null)
            //    return;

            List<String> ListeNamespace = new List<String>();

            string[] ar = type.FullName.Split('.');
            string nn = ar[ar.Count() - 1];

            if (ar.Count() >= 2)
                nn = ar[ar.Count() - 2] + "." + nn;

            string file = filepath + nn + ".cs";
            if (Override && System.IO.File.Exists(file))
                return;

            using (System.IO.StreamWriter st = new System.IO.StreamWriter(file))
            {
                StringBuilder s = new StringBuilder();
                ListeNamespace.Add("devtm.Configuration.Designers");
                
                s.AppendLine("namespace " + Namespace);                
                s.AppendLine("{");
                s.AppendLine("");

                s.AppendLine(string.Format(CultureInfo.CurrentCulture, "    [TemplateDesignerAttribute(\"{0}\", @\"{1}\")]", type.AssemblyQualifiedName, context));
                s.AppendLine(string.Format(CultureInfo.CurrentCulture, "    public interface I{0}", type.FullName.Replace(".", "")));
                s.AppendLine("  {");


                TaskProperties(type, s, ListeNamespace);

                s.AppendLine("  }");
                s.AppendLine("");
                s.AppendLine("}");


                foreach (string  n in ListeNamespace)
                    st.WriteLine("using " + n + ";");

                st.Write(s.ToString());
                st.Close();
            }

        }

        private static void TaskProperties(Type type, StringBuilder s, List<String> ListeNamespace)
        {

            System.Text.RegularExpressions.Regex Reg = new System.Text.RegularExpressions.Regex("[A-Z]+[a-z]*");

            foreach (PropertyInfo item in type.GetProperties())
            {
                if (item.PropertyType.FullName.StartsWith("System.Configuration") || 
                    item.PropertyType.IsOfType(
                    typeof(ConfigurationElement),
                    typeof(System.Configuration.ElementInformation),
                    typeof(System.Configuration.Configuration),
                    typeof(System.Configuration.ConfigurationLockCollection)
                    )
                    || item.Name == "LockItem"
                    || item.Name == "IsSynchronized"
                    || item.Name == "SyncRoot"
                    || item.Name == "EmitClear"
                    )
                    continue;
                s.AppendLine("  ");

                bool a1 = false;
                bool a2 = false;
                foreach (Attribute attr in Attribute.GetCustomAttributes(item))
                {

                    if (attr is DisplayNameAttribute)
                        a1 = true;

                    if (attr is DescriptionAttribute)
                        a2 = true;

                    TaskAttribute(attr, s, ListeNamespace);
                }


                if (!a1)
                {
                    string b1 = "[DisplayName(\"";
                    foreach (Match t in Reg.Matches(item.Name))
                        b1 = b1 + t.Value + " ";
                    b1 = b1.Trim() + "\")]";
                    s.AppendLine("        //" + b1);
                }

                if (!a2)
                    s.AppendLine("        //[Description(\"\")]");
                

                if (!ListeNamespace.Contains(item.PropertyType.Namespace))
                    ListeNamespace.Add(item.PropertyType.Namespace);

                string typemethod = item.PropertyType.Name;
                string nam2 = item.Name;
                string Get = item.CanRead ? "get;" : string.Empty;
                string Set = item.CanRead ? "set;" : string.Empty;
                s.AppendLine(string.Format(CultureInfo.CurrentCulture, "        {0} {1} {4} {2} {3} {5}", typemethod, nam2, Get, Set, "{", "}"));
            }
        }

        private static void TaskAttribute(Attribute attribute, StringBuilder s, List<String> ListeNamespace)
        {
            if (attribute.GetType().FullName.StartsWith("System.Configuration") ||
                attribute.GetType().IsOfType(
                typeof(System.Configuration.SectionInformation)
                ))
                return;

            Type type = attribute.GetType();
            string listeproperties = "(";
            List<string> lst = new List<string>();
            foreach (ConstructorInfo item in type.GetConstructors())
            {
                foreach (ParameterInfo para in item.GetParameters())
                {
                    lst.Add(para.Name);
                    PropertyInfo prop = null;
                    foreach (PropertyInfo iio in type.GetProperties())
                        if (iio.Name.ToLower() == para.Name.ToLower())
                        {
                            prop = iio;
                            break;
                        }
                    

                    if (prop == null)
                        return;

                    if (prop.PropertyType.IsOfType(typeof(System.Configuration.ConfigurationValidatorBase)))
                        return;

                    try
                    {
                        var value= prop.GetValue(attribute, null);
                        value = TaskValue(type, value, ListeNamespace);
                        listeproperties = listeproperties + value + ", ";
                    }
                    catch (Exception)
                    {
                        throw;
                    }

                }
                break;
            }

            foreach (PropertyInfo item in type.GetProperties())
            {
                if (lst.Contains(item.Name.ToLower()))
                    continue;
                if (!item.CanWrite)
                    continue;

                if (!(item.PropertyType == typeof(string)))
                    if (item.PropertyType.IsClass)
                        continue;

                try
                {
                    var value = item.GetValue(attribute, null);
                    value = TaskValue(type, value, ListeNamespace);
                    listeproperties = listeproperties + item.Name + " = " + value.ToString() + ", ";
                }
                catch (Exception)
                {
                    throw;
                }
                

            }

            if (!string.IsNullOrEmpty(listeproperties) && listeproperties.Length >= 2)
            listeproperties = listeproperties.Substring(0, listeproperties.Length - 2) + ")";

            if (!ListeNamespace.Contains(type.Namespace))
                ListeNamespace.Add(type.Namespace);

            s.AppendLine(String.Format(CultureInfo.CurrentCulture,
                   "        //[{0}{1}]"
                   , type.Name
                   , listeproperties
                   ));

        }

        private static object TaskValue<T>(Type type, T value, List<String> ListeNamespace)
        {
            if (value == null)
                return "";

            if (value is string)
                return "\"" + value.ToString() + "\"";


            if (value is bool)
                return value.ToString().ToLower();


            else if (value.GetType().IsEnum)
            {
                if (!ListeNamespace.Contains(value.GetType().Namespace))
                    ListeNamespace.Add(value.GetType().Namespace);

                string r = string.Empty;
                foreach (string ii in  value.ToString().Split(','))
                {
                    r = r + value.GetType().Name + "." + ii.Trim() + " | ";
                }
                if (!string.IsNullOrEmpty(r) && r.Length >= 2)
                    r = r.Substring(0, r.Length - 2);
                return r;
            }


            else
                return value.ToString();
            
        }



        //private static Type[] types = new Type[] { typeof(object), typeof(IElementSection) };
        //public static IEnumerable<CustomDesignerAction> CreateTemplateCode(this CustomDesignerAction[] list, MethodInfo method, IElementSection section)
        //{

        //    List<MethodInfo> lst;
        //    // on tourne dans la liste des attributs de la method
        //    foreach (CustomDesignerAction a in list)
        //    {


        //        if (!string.IsNullOrEmpty(a.ViewFor))
        //        {

        //            MethodInfo m = null;

        //            try
        //            {

        //                lst = a.Type.GetMethods(BindingFlags.Static | BindingFlags.Public)
        //                    .Where(i => (i.Name == a.ViewFor)
        //                        && (i.GetParameters().Length == 1)
        //                        && types.Contains(i.GetParameters().First().ParameterType)
        //                        ).ToList();

        //                if (lst.Count > 1)
        //                    throw new Exception(string.Format("More one method match for {0}.{1} with object or IElementSection argument.", a.Type, a.ViewFor));

        //                m = lst.First();

        //            }

        //            catch (Exception ex)
        //            {
        //                // Datas.NotifyError(m, ex);
        //                continue;
        //            }

        //            bool ret = (bool)m.Invoke(null, new object[] { section });
        //            if (!ret)
        //                continue;

        //            yield return m;
        //        }
        //    }
        //}


      

        #region IsOfType

        /// <summary>
        /// Istypes the specified type.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="searchtype">The searchtype.</param>
        /// <returns></returns>
        private static bool IsOfType(this Type type, Type searchtype)
        {
            if (type == null || searchtype == null)
                return false;

            if (searchtype.IsClass)
                return type == searchtype || type.IsSubclassOf(searchtype);
            else if (searchtype.IsInterface)
                return (type.GetInterface(searchtype.FullName, true) != null);
            return false;
        }


        private static bool IsOfType(this Type type, params Type[] searchtypes)
        {

            foreach (Type searchtype2 in searchtypes)
                if (IsOfType(type, searchtype2))
                    return true;

            return false;
        }

        #endregion

    }

}
